package org.newlucene.core.search;

import java.io.IOException;

import org.newlucene.core.index.*;

public abstract class PhraseSearcher extends IndexSearcher
{
    protected PhraseQueue pq;

    protected PhrasePositions first, last;
    
    private TermSearcher termSearcher;

    private int numTerms;
    
    PhraseSearcher(IndexReader indexReader, Term[] terms) throws IOException
    {
    	super(indexReader);
    	if (terms.length == 0)
    	{
    		throw new IOException("Terms length is 0");
    	}
    	else if (terms.length == 1)
    	{
    		termSearcher = new TermSearcher(indexReader, terms[0]);
    	}
    	else
    	{
    		this.numTerms = terms.length;
    		
            // get all term positions for the terms
            TermPostings[] tps = new TermPostings[terms.length];
            for (int i = 0; i < terms.length; i++)
            {
                TermPostings p = indexReader.termPositions(terms[i]);
                tps[i] = p;
            }
            
            // use PQ to build a sorted list of PhrasePositions
            pq = new PhraseQueue(tps.length);
            for (int i = 0; i < tps.length; i++)
            {
                pq.put(new PhrasePositions(tps[i], i));
            }
            pqToList();    		
    	}
    }

    protected void search(HitCollector hc, int end) throws IOException
    {
    	if (termSearcher != null)
    	{
    		termSearcher.search(hc, end);
    	}
    	else
    	{
    		doRealSearch(hc, end);
    	}
    }
    
    private void doRealSearch(HitCollector hc, int end) throws IOException
    {
    	while (last.doc < end)
        { // find doc w/ all the terms
            while (first.doc < last.doc)
            { // scan forward in first
                do
                {
                    first.next();
                }
                while (first.doc < last.doc);
                firstToLast();
                if (last.doc >= end) return;
            }

            // found doc with all terms
            float freq = phraseFreq(); // check for phrase

            if (freq > 0.0)
            {
            	float score = freq * boost;
//            	float score = Similarity.tf(freq); // compute score
//                score *= boost;
                hc.collect(first.doc, score); // add to results
            }
            last.next(); // resume scanning
        }
    }

    abstract protected float phraseFreq() throws IOException;

    protected final void firstToLast()
    {
        last.next = first; // move first to end of list
        last = first;
        first = first.next;
        last.next = null;
    }

    protected final void pqToList()
    {
        last = first = null;
        while (pq.top() != null)
        {
            PhrasePositions pp = (PhrasePositions) pq.pop();
            if (last != null)
            { // add next to end of list
                last.next = pp;
            }
            else
                first = pp;
            last = pp;
            pp.next = null;
        }
    }
}